<?php
namespace ZyucMini\Core;

/**
 * 路由类 - 负责URL路由和请求分发
 * - 支持动态方法注册 get/post/put/delete等
 * - 支持 group 分组
 * - 支持路由参数解析
 */
class Router
{
	/**
	 * 路由表（实例级）
	 * @var array
	 */
	protected $routes = [];

	/**
	 * 实例分组前缀
	 * @var string
	 */
	protected $instanceGroupPrefix = '';

	/**
	 * 支持的HTTP方法列表
	 * @var array
	 */
	protected $supportedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];

	/**
	 * 动态方法调用：支持实例化后调用 $router->get(...) / $router->post(...) 等
	 * @param string $name 方法名
	 * @param array $arguments 参数数组
	 * @return Router
	 * @throws \BadMethodCallException
	 */
	public function __call($name, $arguments)
	{
		// 特殊支持 group 实例方法（并不是 HTTP 方法）
		if ($name === 'group') {
			if (!isset($arguments[0]) || !isset($arguments[1]) || !is_callable($arguments[1])) {
				throw new \BadMethodCallException("Invalid arguments for group");
			}
			return $this->group($arguments[0], $arguments[1]);
		}

		$method = strtoupper($name);
		if (!in_array($method, $this->supportedMethods)) {
			throw new \BadMethodCallException("Unsupported router method: $name");
		}

		$path = $arguments[0] ?? '/';
		$handler = $arguments[1] ?? null;

		if ($handler === null) {
			throw new \InvalidArgumentException("Handler cannot be null");
		}

		// 合并实例前缀
		$prefix = $this->instanceGroupPrefix;
		$fullPath = rtrim($prefix, '/') . '/' . ltrim($path, '/');
		$fullPath = $this->normalizePath($fullPath);

		$this->routes[] = [
			'method' => $method,
			'path' => $fullPath,
			'handler' => $handler,
		];
		return $this;
	}

	/**
	 * 路由分组：接受前缀和回调，回调接收当前 Router 实例
	 * @param string $prefix 路由前缀
	 * @param callable $callable 回调函数
	 * @return Router
	 */
	public function group($prefix, $callable)
	{
		$previous = $this->instanceGroupPrefix;
		$prefix = self::normalizePath($prefix);
		$this->instanceGroupPrefix = rtrim($previous, '/') . '/' . ltrim($prefix, '/');
		$this->instanceGroupPrefix = self::normalizePath($this->instanceGroupPrefix);

		try {
			// 执行回调，允许回调使用 $this->get / $this->post
			$callable($this);
		} finally {
			// 确保前缀被恢复，即使回调中发生异常
			$this->instanceGroupPrefix = $previous;
		}
		return $this;
	}

	/**
	 * 分发当前请求
	 * @return bool 是否成功匹配并执行路由
	 */
	public function dispatch()
	{
		$request = $this->getCurrentRequest();
		
		foreach ($this->routes as $route) {
			if ($route['method'] !== $request['method']) {
				continue;
			}

			$params = [];
			if ($this->match($route['path'], $request['path'], $params)) {
				$this->executeHandler($route['handler'], $params);
				return true;
			}
		}

		// 未命中任何路由
		$this->handleNotFound();
		return false;
	}

	/**
	 * 获取当前请求信息
	 * @return array
	 */
	protected function getCurrentRequest()
	{
		$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
		$uri = $_SERVER['REQUEST_URI'] ?? '/';
		$path = parse_url($uri, PHP_URL_PATH) ?: '/';
		$path = $this->normalizePath($path);
		
		return [
			'method' => $method,
			'path' => $path,
			'uri' => $uri
		];
	}

	/**
	 * 执行路由处理器
	 * @param mixed $handler 处理器
	 * @param array $params 路由参数
	 * @return void
	 */
	protected function executeHandler($handler, $params)
	{
		if (is_callable($handler)) {
			// 直接传入解析到的 params（如果没有参数则为空数组）
			call_user_func_array($handler, $params);
		} elseif (is_string($handler)) {
			// 支持 Controller@method 形式
			if (strpos($handler, '@') !== false) {
				[$class, $methodName] = explode('@', $handler, 2);
				if (class_exists($class)) {
					$obj = new $class();
					if (method_exists($obj, $methodName)) {
						call_user_func_array([$obj, $methodName], $params);
					} else {
						throw new \BadMethodCallException("Method {$methodName} not found in class {$class}");
					}
				} else {
					throw new \InvalidArgumentException("Class {$class} not found");
				}
			} else {
				throw new \InvalidArgumentException("Invalid handler format: {$handler}");
			}
		} else {
			throw new \InvalidArgumentException("Handler must be callable or string");
		}
	}

	/**
	 * 处理404错误
	 * @return void
	 */
	protected function handleNotFound()
	{
		header("HTTP/1.1 404 Not Found");
		echo "404 Not Found";
	}

	/**
	 * 路径匹配：支持 :param 风格的占位符
	 * @param string $routePath 路由路径
	 * @param string $requestPath 请求路径
	 * @param array &$params 输出参数数组
	 * @return bool 是否匹配成功
	 */
	protected function match($routePath, $requestPath, &$params)
	{
		$routeParts = explode('/', trim($routePath, '/'));
		$reqParts = explode('/', trim($requestPath, '/'));

		if (count($routeParts) !== count($reqParts)) {
			return false;
		}

		$params = [];
		foreach ($routeParts as $i => $part) {
			if (strlen($part) > 0 && $part[0] === ':') {
				$key = substr($part, 1);
				$params[$key] = $reqParts[$i];
				continue;
			}

			if ($part !== $reqParts[$i]) {
				return false;
			}
		}

		// 返回参数时以数值索引为主，保留名字索引
		$params = array_values($params);
		return true;
	}

	/**
	 * 标准化路径：确保路径格式正确
	 * @param string $path 原始路径
	 * @return string 标准化后的路径
	 */
	protected function normalizePath($path)
	{
		if ($path === '' || $path === null) {
			return '/';
		}
		$p = '/' . trim($path, '/');
		return $p === '//' ? '/' : $p;
	}

	/**
	 * 获取所有注册的路由
	 * @return array
	 */
	public function getRoutes()
	{
		return $this->routes;
	}

	/**
	 * 清空所有路由
	 * @return Router
	 */
	public function clearRoutes()
	{
		$this->routes = [];
		return $this;
	}
}

